<template>
    <div class="directory d-flex flex-column">
        <nav class="text-left p-2 controller bg-white d-flex align-items-center">
            
            <div class="dropdown d-inline-block mr-auto" v-if="root_id">
                <button class="btn btn-link text-dark bg-white btn-sm p-0" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    <i class="material-icons align-middle">list</i>
                </button>
                <div class="dropdown-menu p-0" style="min-width: unset;">
                    <ol class="breadcrumb m-0 flex-wrap" style="white-space: nowrap; width: 50vw;">
                        <li class="breadcrumb-item" v-if="rootDoc"><a href="#" @click.prevent="jump(-1)">{{rootDoc.name}}</a></li>
                        <li class="breadcrumb-item"
                            :class="{active: index == reverseStack.length - 1}"
                            style="white-space: nowrap;" 
                            v-for="(doc, index) in reverseStack">
                            <a href="#" @click.prevent="jump(index)">
                                {{doc.name}}
                            </a>
                        </li>
                    </ol>
                </div>
                
            </div>
            <button class="btn btn-outline-light text-success btn-sm p-1 mx-1" type="button" v-if="!isRecycleView && editable"
                title="进入回收站" v-tooltip
                @click="$emit('update:url', constant.RECYCLE_DIRECTORY_URL)">
                <i class="material-icons align-middle">restore_from_trash</i>
            </button>
            <template v-if="isEditValid">
                <template v-if="editing">
                    <button class="btn btn-sm btn-light p-1 text-success" @click="$emit('create', activeId, reload)" title="新建目录" v-tooltip>
                        <i class="material-icons align-middle">create_new_folder</i>
                    </button>
                    <button class="btn btn-sm text-danger btn-light p-1 mx-1"
                        v-if="parentId"
                        @click.stop="$emit('remove', parentId, activeItem, back)" title="移除目录" v-tooltip>
                        <i class="material-icons align-middle">delete</i>
                    </button>
                    <button class="btn btn-sm btn-light p-1 mx-1" @click="editing = !editing"  title="退出编辑模式" v-tooltip>
                        <i class="material-icons align-middle">close</i>
                    </button>
                </template>
                <template v-else>
                    <button class="btn btn-sm btn-light p-1" @click="editing = !editing" title="进入编辑模式" v-tooltip>
                        <i class="material-icons align-middle">edit</i>
                    </button>
                </template>
            </template>
            
            <template v-if="isRecycleView">
                <button class="btn btn-link ml-auto btn-sm p-1" type="button" v-if="url != constant.RECYCLE_DIRECTORY_URL"
                    title="进入目录回收站" v-tooltip
                    @click="$emit('update:url', constant.RECYCLE_DIRECTORY_URL)">
                    <i class="material-icons align-middle">folder</i>
                </button>
                <button class="btn btn-link ml-auto btn-sm p-1" type="button" v-else
                    title="进入图片回收站" v-tooltip
                    @click="$emit('update:url', constant.RECYCLE_IMAGE_URL)">
                    <i class="material-icons align-middle">image</i>
                </button>
            </template>
                
            <button class="btn btn-link text-dark btn-sm p-1 mx-1" type="button" v-if="isRecycleView"
                title="退出回收站" v-tooltip
                @click="$emit('update:url', constant.ROOT_URL)">
                <i class="material-icons align-middle">close</i>
            </button>
        </nav>
        <div class="curName d-inline-block text-muted font-italic d-flex align-items-center">
            <span class="mr-auto">{{activeItem ? activeItem.name : "加载中"}}</span>
            <button class="btn btn-sm btn-link text-info p-1 mx-1" @click="back" :class="{disabled: !stack.length}" v-if="stack.length" title="回到上一级" v-tooltip>
                <i class="material-icons align-middle">arrow_back_ios</i>
            </button>
            <button class="btn btn-outline-light text-success btn-sm p-1 mx-1" type="button" v-if="parentId"
                title="定位于父目录中" v-tooltip
                @click="focusInParent">
                <i class="material-icons align-middle">gps_fixed</i>
            </button>
            <button class="btn btn-sm btn-light p-1 mx-1" @click.prevent="e => smartIn(e.ctrlKey, null)">
                <i class="material-icons align-middle" title="进入下一个目录" v-tooltip>arrow_downward</i>
            </button>
            <button class="btn btn-sm btn-light p-1 mx-1" @click.prevent="reload()">
                <i class="material-icons align-middle" title="刷新" v-tooltip>refresh</i>
            </button>
        </div>
        <div class="list-container flex-grow-1">
            <transition :name="animateName" @after-enter="listRendered.fire">
                <list :arr="dirs" @click="itemClick" :key="ajaxUID" :class="{searching}" :editing="editing">
                <template slot="editbar" slot-scope="{doc,index}">
                    <template v-if="isRecycleView">
                        <button class="btn btn-sm btn-link p-1 ml-auto" @click.stop="$emit('rename', doc, reload)">
                            <i class="material-icons align-middle" title="重命名" v-tooltip>edit</i>
                        </button>
                        <button class="btn btn-sm btn-link p-1 mx-1" @click.stop="$emit('move', activeId, doc, reload)">
                            <i class="material-icons align-middle" title="还原至..." v-tooltip>restore</i>
                        </button>
                        <button class="btn btn-sm text-danger p-1 mx-1" :class="[index % 2 ? 'bg-dark' : 'bg-light']"
                            v-if="activeId == root_id"
                            @click.stop="$emit('remove', activeId, doc, reload)" title="销毁目录" v-tooltip>
                            <i class="material-icons align-middle">delete</i>
                        </button>
                    </template>
                    <template v-else>
                        <button class="btn btn-sm btn-link p-1 ml-auto" @click.stop="$emit('rename', doc, reload)">
                            <i class="material-icons align-middle" title="重命名" v-tooltip>edit</i>
                        </button>
                        <button class="btn btn-sm btn-link p-1 mx-1" @click.stop="$emit('move', activeId, doc, reload)">
                            <i class="material-icons align-middle" title="移动" v-tooltip>move_to_inbox</i>
                        </button>
                        <button class="btn btn-sm text-danger p-1 mx-1" :class="[index % 2 ? 'bg-dark' : 'bg-light']"
                            @click.stop="$emit('remove', activeId, doc, reload)" title="移除目录" v-tooltip>
                            <i class="material-icons align-middle">delete</i>
                        </button>
                    </template>
                </template>
                </list>
            </transition>
        </div>
        <loading :active="isLoading || searching"
            backgroundColor='transparent'
            :can-cancel="false"
            :is-full-page="false"></loading>
    </div>
</template>
<script type="text/javascript">
import $ from 'jquery'
import Scrollbar from 'smooth-scrollbar';

import jqAjax from '../plugin/jqAjax'
import {constant as ajaxConstant} from '../plugin/jqAjax'

import list from './directory-list'

import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/vue-loading.css';

var constant = Object.assign({
    ANIMATENEXT: 'list-next',
    ANIMATEBACK: 'list-back',
    ANIMATEJUMP: 'list-jump',
    ANIMATEHOLD: 'list-hold',
    ROOT_URL: '/model/directory/list/root',
    RECYCLE_DIRECTORY_URL: '/model/directory/list/recycle/directory',
    RECYCLE_IMAGE_URL: '/model/directory/list/recycle/image',
}, ajaxConstant)


export {constant};

export default {
    name: 'directory',
    components: {list, Loading},
    props: {
        editable: {
            type: Boolean,
            default: true
        },
        url: {
            type: String,
            default: constant.ROOT_URL
        }
    },
    mixins: [jqAjax],
    data() {
        var vm = this;
        return {
            root_id: null,
            rootDoc: null,
            stack: [],
            dirs: [],
            searching: false,
            real_editing: false,
            animateName: constant.ANIMATEJUMP,
            constant,
            listRendered: $.Callbacks("unique stopOnFalse")
        }
    },
    computed: {
        isEditValid() {
            return this.isRecycleView ? false : this.editable;
        },
        isLoading() {
            return this.state == constant.LOADING || this.searching;
        },
        editing: {
            get() {
                return this.isRecycleView ? true : this.editable && this.real_editing;
            },
            set(nv) {
                this.real_editing = nv;
            }
        },
        isRecycleView() {
            return this.url == constant.RECYCLE_IMAGE_URL || this.url == constant.RECYCLE_DIRECTORY_URL;
        },
        reverseStack() {
            return this.stack.slice().reverse();
        },
        stackKey() {
            return this.stack.length ? this.stack[0]._id : this.root_id;
        },
        activeItem() {
            return this.stack.length ? this.stack[0] : this.rootDoc;
        },
        activeId() {
            return this.activeItem ? this.activeItem._id : this.root_id;
        },
        parentId() {
            if (!this.stack.length) {
                return null;
            }
            return this.stack.length > 1 ? this.stack[1] : this.root_id;
        }
    },
    methods: {
        fresh: function() {
            var vm = this;
            
            if (!vm.root_id || !vm.stack.length) {
                return vm.getRoot();
            } else {
                return vm.list();
            }
        },
        reload() {
            var vm = this;
            vm.animateName = constant.ANIMATEJUMP;
            return vm.fresh();
        },
        async loadChildDirsImage(selfObj) {
            var vm = this,childContents = [], queue = vm.dirs.slice();
            while (queue.length) {
                var cur = queue.shift();
                childContents.push.apply(childContents, cur.content);

                var n_res = await vm.ajaxPost('/model/directory/list', {_id: cur._id});
                queue.unshift.apply(queue, n_res.dirs);
            }
            vm.activeItem.content = selfObj.content.slice().concat(childContents);
        },
        getRoot() {
            var vm = this;
            
            return vm.ajaxPost(vm.url)
            .done(function(res) {
                vm.root_id = res.rootId;
                vm.rootDoc = res.root;
                vm.dirs = res.dirs;
            })
        },
        list: function() {
            var vm = this;
            
            return vm.ajaxPost('/model/directory/list', {_id: vm.stack[0]._id})
            .done(async function(res) {
                if (res.self.__v != vm.activeItem.__v) {
                    vm.stack.shift();
                    vm.stack.unshift(res.self);
                }
                vm.dirs = res.dirs;
                // vm.loadChildDirsImage(res.self);
            })
        },
        itemClick(doc) {
            return this.push(doc);
        },
        push(doc) {
            var vm = this;
            if (vm.state !== constant.IDLE) {
                return;
            }
            vm.animateName = constant.ANIMATENEXT;
            vm.stack.unshift(doc);
            return vm.fresh()
            .fail(function() {
                vm.stack.shift();
            });
        },
        jump(index) {
            var vm = this;
            if (vm.state !== constant.IDLE) {
                return;
            }
            if (index == -1) {
                vm.stack = [];
            } else {
                vm.stack = vm.stack.slice(-(index + 1));    
            }
            vm.animateName = constant.ANIMATEJUMP;
            return vm.fresh();
        },
        back() {
            var vm = this;
            if (vm.state !== constant.IDLE) {
                return;
            }
            if (vm.stack.length < 1) {
                return;
            } else {
                return vm.jump(vm.stack.length - 2).done(function() {
                    vm.animateName = constant.ANIMATEBACK;            
                });
            }
        },
        async smartIn(skipEmptyContent=true, cb) {
            var vm = this, nextIndex, target;
            if (vm.searching) {
                return;
            }
            vm.searching = true;
            try {
                target = vm.dirs;
                nextIndex = 0;
                while (nextIndex < 0 || nextIndex >= target.length) {
                    var cur = vm.activeItem;
                    if (vm.parentId) {
                        await vm.back().done(() => {
                            vm.animateName = constant.ANIMATEHOLD;
                        });
                    } else {
                        nextIndex = -1;
                        break;
                    }
                    nextIndex = vm.dirs.findIndex(function(x) {
                        return x._id == cur._id;
                    });
                    if (nextIndex != -1) {
                        nextIndex = nextIndex + 1;
                    }
                    target = vm.dirs;
                }
                if (nextIndex >= 0 && nextIndex < target.length) {
                    await vm.push(target[nextIndex]).done(() => {
                        vm.animateName = constant.ANIMATEJUMP;
                    });
                    vm.searching = false;
                    if (skipEmptyContent && !vm.activeItem.content.length) {
                        return vm.smartIn.apply(vm, arguments);
                    }
                    cb && cb(null);
                } else {
                    vm.searching = false;
                    cb && cb('not found');
                }
            } catch(e) {
                vm.searching = false;
                cb && cb(e);
            }
        },
        async focusInParent() {
            var vm = this, cur = vm.activeItem;
            if (!vm.parentId) {
                return;
            }
            await vm.back();
            var i = vm.dirs.findIndex(x => x._id == cur._id);
            vm.listRendered.add(function(el) {
                i != -1 && vm.$nextTick(() => {
                    vm.scrollbar.update();
                    var offset = vm.scrollbar.contentEl.getBoundingClientRect(),
                        rect = el.children[i].getBoundingClientRect();
                    var xi = rect.left - offset.left, yi = rect.top - offset.top;
                    vm.scrollbar.scrollTo(vm.scrollbar.scrollLeft + xi, vm.scrollbar.scrollTop + yi);
                    el.children[i] && el.children[i].focus();
                })
                vm.listRendered.empty();
            })
            
        }
    },
    watch: {
        url(nv, ov) {
            var vm = this;
            vm.stack = [];
            vm.root_id = null;
            vm.rootDoc = null;
            vm.dirs = [];
            vm.reload();
        }
    },
    created() {
        var vm = this;
        vm.fresh();
        vm.succeed.add(function() {
            vm.$nextTick(function() {
                vm.$emit('fresh', vm.activeItem);
            });
        })
    },
    mounted() {
        var vm = this;
        vm.scrollbar = Scrollbar.init(this.$el.querySelector('.list-container'));
    },
    destroyed() {
        var vm = this;
        vm.scrollbar && vm.scrollbar.destroy();
    }
}
</script>

<style type="text/css" scoped>
.directory {
    position: relative;
}

.controller {
    height: 3.5rem;
}

.list {
    transition: all .5s;
    position: absolute;
    left: 0;
    right: 0;
}

.list-jump-leave,
.list-back-enter,
.list-next-enter {
    z-index: 1;
}

.list-next-enter,
.list-back-leave-to {
    transform: translate(-100%, 0);
    opacity: 0;
}

.list-next-enter-to {
    transform: translate(0, 0);
    opacity: 1;
}

.list-back-enter,
.list-jump-leave-to,
.list-next-leave-to {
    opacity: 0;
}

.list-jump-enter-to,
.list-back-enter-to {
    opacity: 1;
}

.list-hold-enter-to,
.list-hold-leave-to {
    opacity: 0;
}

</style>